﻿using System;
using System.Collections.Generic;
using System.Data.Entity.Migrations;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WikeSoft.WorkFlowEngine.Entities;
using WikeSoft.WorkFlowEngine.Enum;
using WikeSoft.WorkFlowEngine.Extension;
using WikeSoft.WorkFlowEngine.Filter;
using WikeSoft.WorkFlowEngine.Interfaces;
using WikeSoft.WorkFlowEngine.Models;
using WikeSoft.WorkFlowEngine.Msg;
using WikeSoft.WorkFlowEngine.Tools;
using Task = WikeSoft.WorkFlowEngine.Models.Task;

namespace WikeSoft.WorkFlowEngine.AppServices
{
    /// <summary>
    /// 流程实例
    /// </summary>
    public class WorkFlowInstanceService : IWorkFlowInstanceService
    {



        #region public method

        /// <summary>
        /// 创建实例
        /// </summary>
        /// <param name="parms"></param>
        /// <returns></returns>
        public InstanceMessage CreateInstance(CreateParms parms)
        {
            InstanceMessage instanceMessage = new InstanceMessage();
            try
            {
                using (var context = new WorkFlowDbContext())
                {
                    var flowdef = context.WorkFlowDefs.FirstOrDefault(c => c.WorkFlowDefKey == parms.FlowDefKey);
                    if (flowdef == null)
                    {
                        throw new Exception(string.Format("创建流程实例失败，找不到flowDefKey:{0}", parms.FlowDefKey));
                    }

                    WorkFlowModel data = GetCurrentVersionFlow(flowdef.Id);
                    var startNode = data.Nodes.FirstOrDefault(c => c.FlowDefId == flowdef.Id && c.NodeType == NodeType.Start);

                    if (startNode == null)
                    {
                        throw new Exception(string.Format("创建流程实例失败，找不到起始节点:{0}", parms.FlowDefKey));
                    }
                    var nodelinks = data.NodeLinks.Where(c => c.SourceId == startNode.Id).ToList();
                    if (nodelinks.Count == 0)
                    {
                        throw new Exception(string.Format("创建流程实例失败，找不到连接线:{0}", startNode.NodeDefName));
                    }
                    TaskDefinition targetNode = getTargetNode(data, nodelinks, parms.Condition);
                    if (targetNode == null)
                    {
                        throw new Exception("创建流程实例失败，未知的目标节点");
                    }

                    if (String.IsNullOrEmpty(parms.TargetUserId))
                    {
                        throw new Exception(string.Format("【{0}】环节找不到处理人", targetNode.NodeDefName));
                    }

                    if (targetNode.NodeType != NodeType.Task)
                    {
                        throw new Exception(string.Format("创建流程实例失败，节点{0}的类型只能为任务类型", targetNode.NodeDefName));
                    }
                    WorkFlowInstance record = new WorkFlowInstance();
                    record.Id = Guid.NewGuid().ToString().ToUpper();
                    record.WorkFlowDefId = flowdef.Id;
                    record.CreateUser = parms.UserName;
                    record.ObjectId = parms.ObjectId.ToUpper();
                    record.InstanceName = parms.InstanceName;
                    record.CreateUserId = parms.UserId.ToUpper();
                    record.CreateTime = DateTime.Now;
                    record.RunStatus = FlowRunStatus.Run;
                    record.AssociatedUserId = parms.AssociatedUserId;
                    record.OtherParams = parms.OtherParams;
                    var flowFlowVersion = flowdef.WorkFlowVersions.OrderByDescending(c => c.VersionNumber).FirstOrDefault();
                    if (flowFlowVersion == null)
                    {
                        throw new Exception("创建流程实例失败，找不到流程的版本");
                    }
                    record.Version = flowFlowVersion.VersionNumber;
                    //添加流程记录
                    context.WorkFlowInstances.Add(record);




                    WorkFlowTask startTask = new WorkFlowTask();
                    startTask.RunStatus = FlowRunStatus.History;
                    startTask.Id = Guid.NewGuid().ToString().ToUpper();
                    startTask.InstanceId = record.Id;
                    startTask.NodeDefId = startNode.Id;
                    startTask.DealUserId = parms.UserId;
                    startTask.DealDate = DateTime.Now;
                    startTask.DealUser = parms.UserName;
                    if (parms.Remark == null)
                    {
                        startTask.DealRemark = "发起申请";
                    }
                    else
                    {
                        startTask.DealRemark = parms.Remark;
                    }
                    
                    //添加节点类型
                    context.WorkFlowTasks.Add(startTask);


                    WorkFlowTask nodeRecord = new WorkFlowTask();
                    nodeRecord.RunStatus = FlowRunStatus.Run;
                    nodeRecord.Id = Guid.NewGuid().ToString().ToUpper();
                    nodeRecord.InstanceId = record.Id;
                    nodeRecord.NodeDefId = targetNode.Id;
                    nodeRecord.TargetUserId = parms.TargetUserId.ToUpper();
                    //添加节点类型
                    context.WorkFlowTasks.Add(nodeRecord);
                    context.SaveChanges();
                    instanceMessage.FlowId = nodeRecord.InstanceId;
                    instanceMessage.NodeId = nodeRecord.Id;

                }
            }
            catch (Exception ex)
            {
                instanceMessage.Code = CodeEum.Fail;
                instanceMessage.Message = ex.Message;
            }

            return instanceMessage;
        }

        /// <summary>
        /// 处理流程
        /// </summary>
        /// <param name="auditParams"></param>
        /// <returns></returns>
        public InstanceMessage Complete(AuditParams auditParams)
        {
            InstanceMessage instanceMessage = new InstanceMessage();
            try
            {
                using (var context = new WorkFlowDbContext())
                {
                    var sourcenodeRecord = context.WorkFlowTasks.FirstOrDefault(c => c.Id == auditParams.NodeRecordId);
                    if (sourcenodeRecord == null)
                    {
                        throw new Exception(string.Format("流程处理失败，未找到Flow_NodeRecord的记录:{0}", auditParams.NodeRecordId));

                    }
                    if (sourcenodeRecord.RunStatus == FlowRunStatus.History)
                    {
                        throw new Exception("流程处理失败，流程已被操作过");
                    }
                    else
                    {
                        int version = sourcenodeRecord.WorkFlowInstance.Version;

                        sourcenodeRecord.RunStatus = FlowRunStatus.History;
                        sourcenodeRecord.DealDate = DateTime.Now;
                        sourcenodeRecord.DealUser = auditParams.UserName;
                        sourcenodeRecord.DealUserId = auditParams.UserId;
                        sourcenodeRecord.DealRemark = auditParams.UserMsg;
                        //修改原记录
                        context.WorkFlowTasks.AddOrUpdate(sourcenodeRecord);

                        var flowModel = GetCurrentVersionFlow(sourcenodeRecord.WorkFlowInstance.WorkFlowDefId, version);

                        var flowNodeDef = flowModel.Nodes.FirstOrDefault(c => c.Id == sourcenodeRecord.NodeDefId);

                        if (flowNodeDef != null)
                        {
                            if (auditParams.TaskAudit == TaskAudit.Agree)
                            {
                                var nodelinks = flowModel.NodeLinks.Where(c => c.SourceId == flowNodeDef.Id).ToList();
                                TaskDefinition targetNode = getTargetNode(flowModel, nodelinks, auditParams.Condition);


                                if (targetNode == null)
                                {
                                    throw new Exception("流程处理失败，未知的目标节点");
                                }


                                WorkFlowTask targetnodeRecord = new WorkFlowTask();
                                if (targetNode.NodeType == NodeType.Task)
                                {
                                    if (String.IsNullOrEmpty(auditParams.TargetUserId))
                                    {
                                        throw new Exception(string.Format("【{0}】环节找不到处理人", targetNode.NodeDefName));
                                    }
                                    targetnodeRecord.Id = Guid.NewGuid().ToString().ToUpper();
                                    targetnodeRecord.InstanceId = sourcenodeRecord.InstanceId;
                                    targetnodeRecord.NodeDefId = targetNode.Id;
                                    targetnodeRecord.RunStatus = FlowRunStatus.Run;
                                    targetnodeRecord.TargetUserId = auditParams.TargetUserId.ToUpper();
                                    //添加新记录
                                    context.WorkFlowTasks.Add(targetnodeRecord);

                                    instanceMessage.FlowId = targetnodeRecord.InstanceId;
                                    instanceMessage.NodeId = targetnodeRecord.Id;
                                }
                                else if (targetNode.NodeType == NodeType.End)
                                {
                                    sourcenodeRecord.WorkFlowInstance.RunStatus = FlowRunStatus.History;
                                    context.WorkFlowInstances.AddOrUpdate(sourcenodeRecord.WorkFlowInstance);

                                    instanceMessage.FlowId = sourcenodeRecord.WorkFlowInstance.Id;
                                    instanceMessage.Completed = true;

                                }
                            }
                            else
                            {
                                var nodelinks = flowModel.NodeLinks.Where(c => c.SourceId == flowNodeDef.Id).ToList();
                                TaskDefinition targetNode = getTargetNode(flowModel, nodelinks, auditParams.Condition);


                                if (targetNode == null)
                                {
                                    throw new Exception("流程处理失败，未知的目标节点");
                                } 
                                if (targetNode.NodeType == NodeType.Task)
                                {
                                    sourcenodeRecord.WorkFlowInstance.RunStatus = FlowRunStatus.History;
                                    context.WorkFlowInstances.AddOrUpdate(sourcenodeRecord.WorkFlowInstance);

                                    instanceMessage.FlowId = sourcenodeRecord.WorkFlowInstance.Id;
                                    instanceMessage.Completed = true;
                                }
                                else if (targetNode.NodeType == NodeType.End)
                                {
                                    sourcenodeRecord.WorkFlowInstance.RunStatus = FlowRunStatus.History;
                                    context.WorkFlowInstances.AddOrUpdate(sourcenodeRecord.WorkFlowInstance);

                                    instanceMessage.FlowId = sourcenodeRecord.WorkFlowInstance.Id;
                                    instanceMessage.Completed = true;

                                }
                            }
                            
                        }
                    }
                    context.SaveChanges();

                }
            }
            catch (Exception ex)
            {
                instanceMessage.Message = ex.Message;
                instanceMessage.Code = CodeEum.Fail;
            }


            return instanceMessage;
        }



        public InstanceMessage CompleteToAppointNode(string nodeRecordId, string targetNodeId, string userId, string userName, string userMsg, string targetUserId)
        {
            InstanceMessage instanceMessage = new InstanceMessage();
            try
            {
                using (var context = new WorkFlowDbContext())
                {
                    var sourcenodeRecord = context.WorkFlowTasks.FirstOrDefault(c => c.Id == nodeRecordId);
                    if (sourcenodeRecord == null)
                    {
                        throw new Exception(string.Format("流程处理失败，未找到Flow_NodeRecord的记录:{0}", nodeRecordId));

                    }
                    if (sourcenodeRecord.RunStatus == FlowRunStatus.History)
                    {
                        throw new Exception("流程处理失败，流程已被操作过");
                    }


                    else
                    {
                        int version = sourcenodeRecord.WorkFlowInstance.Version;
                        sourcenodeRecord.RunStatus = FlowRunStatus.History;
                        sourcenodeRecord.DealDate = DateTime.Now;
                        sourcenodeRecord.DealUser = userName;
                        sourcenodeRecord.DealUserId = userId;
                        sourcenodeRecord.DealRemark = userMsg;
                        //修改原记录
                        context.WorkFlowTasks.AddOrUpdate(sourcenodeRecord);

                        var flowModel = GetCurrentVersionFlow(sourcenodeRecord.WorkFlowInstance.WorkFlowDefId, version);

                        var flowNodeDef = flowModel.Nodes.FirstOrDefault(c => c.Id == sourcenodeRecord.NodeDefId);

                        if (flowNodeDef != null)
                        {
                            //var nodelinks = flowModel.NodeLinks.Where(c => c.SourceId == flowNodeDef.Id).ToList();
                            //NodeDef targetNode = nodelinks.FirstOrDefault(c => c.Id == targetNodeId);
                            TaskDefinition targetNode = flowModel.Nodes.FirstOrDefault(c => c.Id == targetNodeId);
                            if (targetNode == null)
                            {
                                throw new Exception("流程处理失败，未知的目标节点");
                            }

                            WorkFlowTask targetnodeRecord = new WorkFlowTask();
                            if (targetNode.NodeType == NodeType.Task)
                            {
                                if (String.IsNullOrEmpty(targetUserId))
                                {
                                    throw new Exception(string.Format("【{0}】环节找不到处理人", targetNode.NodeDefName));
                                }
                                targetnodeRecord.Id = Guid.NewGuid().ToString().ToUpper();
                                targetnodeRecord.InstanceId = sourcenodeRecord.InstanceId;
                                targetnodeRecord.NodeDefId = targetNode.Id;
                                targetnodeRecord.RunStatus = FlowRunStatus.Run;
                                targetnodeRecord.TargetUserId = targetUserId.ToUpper();
                                //添加新记录
                                context.WorkFlowTasks.Add(targetnodeRecord);

                                instanceMessage.FlowId = targetnodeRecord.InstanceId;
                                instanceMessage.NodeId = targetnodeRecord.Id;
                            }
                            else if (targetNode.NodeType == NodeType.End)
                            {
                                sourcenodeRecord.WorkFlowInstance.RunStatus = FlowRunStatus.History;
                                context.WorkFlowInstances.AddOrUpdate(sourcenodeRecord.WorkFlowInstance);

                                instanceMessage.FlowId = sourcenodeRecord.WorkFlowInstance.Id;
                                instanceMessage.Completed = true;

                            }
                        }
                    }
                    context.SaveChanges();

                }
            }
            catch (Exception ex)
            {
                instanceMessage.Message = ex.Message;
                instanceMessage.Code = CodeEum.Fail;
            }


            return instanceMessage;
        }

        public WorkFlowAuthority GetFirstNodeAuthority(string flowDefKey, string condition)
        {
            WorkFlowAuthority authority = new WorkFlowAuthority();

            using (var context = new WorkFlowDbContext())
            {
                var flowdef = context.WorkFlowDefs.FirstOrDefault(c => c.WorkFlowDefKey == flowDefKey);
                if (flowdef == null)
                {
                    throw new Exception(string.Format("找不到flowDefKey:{0}", flowDefKey));
                }

                WorkFlowModel data = GetCurrentVersionFlow(flowdef.Id);
                var startNode = data.Nodes.FirstOrDefault(c => c.FlowDefId == flowdef.Id && c.NodeType == NodeType.Start);

                if (startNode == null)
                {
                    throw new Exception(string.Format("找不到起始节点:{0}", flowDefKey));
                }
                var nodelinks = data.NodeLinks.Where(c => c.SourceId == startNode.Id).ToList();
                if (nodelinks.Count == 0)
                {
                    throw new Exception(string.Format("找不到连接线:{0}", startNode.NodeDefName));
                }
                TaskDefinition targetNode = getTargetNode(data, nodelinks, condition);

                if (targetNode == null)
                {
                    throw new Exception("未知的目标节点");
                }

                if (targetNode.NodeType != NodeType.Task)
                {
                    throw new Exception(string.Format("节点{0}的类型只能为任务类型", targetNode.NodeDefName));
                }
                authority.RoleIds = targetNode.RoleIds;
                authority.RoleNames = targetNode.RoleNames;
                authority.UserIds = targetNode.UserIds;
                authority.UserNames = targetNode.UserNames;

            }
            return authority;
        }

        public WorkFlowAuthority GetNodeAuthority(string nodeRecordId, string targetNodeId)
        {
            WorkFlowAuthority authority = new WorkFlowAuthority();

            using (var context = new WorkFlowDbContext())
            {
                var sourcenodeRecord = context.WorkFlowTasks.FirstOrDefault(c => c.Id == nodeRecordId);
                if (sourcenodeRecord == null)
                {
                    throw new Exception(string.Format("未找到Flow_NodeRecord的记录:{0}", nodeRecordId));

                }
                if (sourcenodeRecord.RunStatus == FlowRunStatus.History)
                {
                    throw new Exception("流程已被操作过");
                }
                else
                {
                    int version = sourcenodeRecord.WorkFlowInstance.Version;

                    //修改原记录
                    context.WorkFlowTasks.AddOrUpdate(sourcenodeRecord);

                    var flowModel = GetCurrentVersionFlow(sourcenodeRecord.WorkFlowInstance.WorkFlowDefId, version);

                    var flowNodeDef = flowModel.Nodes.FirstOrDefault(c => c.Id == sourcenodeRecord.NodeDefId);

                    if (flowNodeDef != null)
                    {
                        //var nodelinks = flowModel.NodeLinks.Where(c => c.SourceId == flowNodeDef.Id).ToList();
                        //NodeDef targetNode = nodelinks.FirstOrDefault(c => c.Id == targetNodeId);
                        TaskDefinition targetNode = flowModel.Nodes.FirstOrDefault(c => c.Id == targetNodeId);
                        if (targetNode == null)
                        {
                            throw new Exception("未知的目标节点");
                        }
                        authority.RoleIds = targetNode.RoleIds;
                        authority.RoleNames = targetNode.RoleNames;
                        authority.UserIds = targetNode.UserIds;
                        authority.UserNames = targetNode.UserNames;

                    }
                }
            }
            return authority;
        }

        

        public List<WorkFlowAuthority> GetAuthorities(string flowDefKey)
        {
            List<WorkFlowAuthority> authoritys = new List<WorkFlowAuthority>();

            using (var context = new WorkFlowDbContext())
            {
                var flowdef = context.WorkFlowDefs.FirstOrDefault(c => c.WorkFlowDefKey == flowDefKey);
                if (flowdef == null)
                {
                    throw new Exception(string.Format("创建流程实例失败，找不到flowDefKey:{0}", flowDefKey));
                }

                WorkFlowModel flowModel = GetCurrentVersionFlow(flowdef.Id);

                var flowNodeDefs = flowModel.Nodes.ToList();

                foreach (TaskDefinition task in flowNodeDefs)
                {
                    WorkFlowAuthority authority = new WorkFlowAuthority();
                    ;
                    authority.RoleIds = task.RoleIds;
                    authority.RoleNames = task.RoleNames;
                    authority.UserIds = task.UserIds;
                    authority.UserNames = task.UserNames;
                    authoritys.Add(authority);
                }
            }
            return authoritys;
          
        }

        public List<TaskInstance> GetRuningFlowInstancesAuthority(string targetUser )
        {
            using (var context = new WorkFlowDbContext())
            {
                var instances = context.WorkFlowTasks.Where(c => c.TargetUserId.ToUpper().Contains(targetUser.ToUpper()) && c.RunStatus == FlowRunStatus.Run )
                    .Select(c => new TaskInstance()
                    {
                        WorkFlowDefId = c.WorkFlowInstance.WorkFlowDef.Id,
                        WorkFlowDefKey = c.WorkFlowInstance.WorkFlowDef.WorkFlowDefKey,
                        WorkFlowDefName = c.WorkFlowInstance.WorkFlowDef.WorkFlowDefName,
                        InstanceId = c.InstanceId,
                        NodeDefId = c.NodeDefId,
                        TaskId = c.Id,
                        DealUserId = c.DealUserId,
                        DealUser = c.DealUser,
                        DealRemark = c.DealRemark,
                        FlowVersion = c.WorkFlowInstance.Version

                    }).ToList();

                foreach (var instance in instances)
                {
                    if (instance != null)
                    {
                        var data = GetCurrentVersionFlow(instance.WorkFlowDefId, instance.FlowVersion);
                        var currentNode = data.Nodes.FirstOrDefault(c => c.Id == instance.NodeDefId);
                        if (currentNode != null)
                            instance.NodeDefName = currentNode.NodeDefName;
                    }

                }

                return instances;
            }
        }

        public FlowMessage DeleteFlowInstance(string flowId)
        {
            FlowMessage instanceMessage = new FlowMessage();
            try
            {
                using (var context = new WorkFlowDbContext())
                {
                    var instance = context.WorkFlowInstances.Find(flowId);

                    if (instance != null)
                    {
                        context.WorkFlowTasks.RemoveRange(instance.WorkFlowTasks);
                        context.WorkFlowInstances.Remove(instance);
                    }

                    context.SaveChanges();

                }
            }
            catch (Exception ex)
            {
                instanceMessage.Code = CodeEum.Fail;
                instanceMessage.Message = ex.Message;
            }

            return instanceMessage;
        }

        public PagedResult<WorkFlowInstanceModel> Query(WorkFlowInstanceFilter filter)
        {
            using (var context = new WorkFlowDbContext())
            {

                var query = context.WorkFlowInstances.AsQueryable();
                if (!string.IsNullOrEmpty(filter.keywords))
                {
                    query = query.Where(c => c.InstanceName.Contains(filter.keywords));
                }
                if (!string.IsNullOrEmpty(filter.CategoryId))
                {
                    var data = context.WorkFlowCategories.Find(filter.CategoryId);
                    if (data != null)
                    {
                        var pathCode = data.PathCode;
                        var ids = context.WorkFlowCategories.Where(c => c.PathCode.StartsWith(pathCode)).Select(x => x.Id);
                        query = query.Where(x => ids.Contains(x.WorkFlowDef.CategoryId));
                    }
                   
                }
                if (filter.FlowRunStatus.HasValue)
                {
                    query = query.Where(c => c.RunStatus == filter.FlowRunStatus);
                }
                if (!string.IsNullOrEmpty(filter.AssociatedUserId))
                {
                    var instanceId = context.WorkFlowTasks.Where(x => x.DealUserId == filter.AssociatedUserId).Select(x=>x.InstanceId);
                    query = query.Where(c => instanceId.Contains(c.Id));
                }
                return query.OrderByCustom(filter.sidx, filter.sord)
                    .Select(item => new WorkFlowInstanceModel
                    {
                        Id = item.Id,
                        FlowDefId =  item.WorkFlowDefId,
                        CreateUser = item.CreateUser,
                        CreateUserId = item.CreateUserId,
                        CreateTime = item.CreateTime,
                        RunStatus = item.RunStatus,
                        Version = item.Version,
                        ObjectId= item.ObjectId,
                        InstanceName = item.InstanceName,
                        AssociatedUserId = item.AssociatedUserId,
                        BusinessUrl = item.WorkFlowDef.BusinessUrl,
                        AuditUrl = item.WorkFlowDef.AuditUrl,
                        CategoryName =  item.WorkFlowDef.WorkFlowCategory.CategoryName,
                        CategoryId =  item.WorkFlowDef.CategoryId,
                        OtherParams = item.OtherParams
                       


                    }).Paging(filter.page, filter.rows);
            }
        }

       

        public WorkFlowAuthority GetNextNodeAuthority(string nodeRecordId, string condition)
        {
            WorkFlowAuthority authority = new WorkFlowAuthority();

            using (var context = new WorkFlowDbContext())
            {
                var sourcenodeRecord = context.WorkFlowTasks.FirstOrDefault(c => c.Id == nodeRecordId);
                if (sourcenodeRecord == null)
                {
                    throw new Exception(string.Format("未找到Flow_NodeRecord的记录:{0}", nodeRecordId));

                }
                if (sourcenodeRecord.RunStatus == FlowRunStatus.History)
                {
                    throw new Exception("流程已被操作过");
                }
                else
                {
                    int version = sourcenodeRecord.WorkFlowInstance.Version;
                    var flowModel = GetCurrentVersionFlow(sourcenodeRecord.WorkFlowInstance.WorkFlowDefId, version);
                    var flowNodeDef = flowModel.Nodes.FirstOrDefault(c => c.Id == sourcenodeRecord.NodeDefId);
                    if (flowNodeDef != null)
                    {

                        var nodelinks = flowModel.NodeLinks.Where(c => c.SourceId == flowNodeDef.Id).ToList();
                        TaskDefinition targetNode = getTargetNode(flowModel, nodelinks, condition);


                        if (targetNode == null)
                        {
                            throw new Exception("未知的目标节点");
                        }

                        authority.RoleIds = targetNode.RoleIds;
                        authority.RoleNames = targetNode.RoleNames;
                        authority.UserIds = targetNode.UserIds;
                        authority.UserNames = targetNode.UserNames;

                    }
                }




            }

            return authority;
        }

        /// <summary>
        /// 得到当前运行的实例
        /// </summary>
        /// <param name="flowId">流程ID</param>
        /// <returns></returns>
        public TaskInstance GetRunFlowInstance(string flowId)
        {
            using (var context = new WorkFlowDbContext())
            {
                var instance = context.WorkFlowTasks.Where(c => c.InstanceId == flowId && c.RunStatus == FlowRunStatus.Run)
                    .Select(c => new TaskInstance()
                    {
                        WorkFlowDefId = c.WorkFlowInstance.WorkFlowDef.Id,
                        WorkFlowDefKey = c.WorkFlowInstance.WorkFlowDef.WorkFlowDefKey,
                        WorkFlowDefName = c.WorkFlowInstance.WorkFlowDef.WorkFlowDefName,
                        InstanceId = c.InstanceId,
                        NodeDefId = c.NodeDefId,
                        TaskId = c.Id,
                        DealUserId = c.DealUserId,
                        DealUser = c.DealUser,
                        DealRemark = c.DealRemark,
                        FlowVersion = c.WorkFlowInstance.Version,
                        TargetUser = c.TargetUserId

                    }).FirstOrDefault();

                if (instance != null)
                {
                    var data = GetCurrentVersionFlow(instance.WorkFlowDefId, instance.FlowVersion);
                    var currentNode = data.Nodes.FirstOrDefault(c => c.Id == instance.NodeDefId);
                    if (currentNode != null)
                        instance.NodeDefName = currentNode.NodeDefName;
                }

                return instance;
            }
        }

        /// <summary>
        /// 得到历史流程处理记录列表
        /// </summary>
        /// <param name="flowId">流程ID</param>
        /// <returns></returns>
        public List<TaskInstance> GetHistoryFlowInstances(string flowId)
        {
            using (var context = new WorkFlowDbContext())
            {
                var instance =
                    context.WorkFlowTasks.Where(c => c.InstanceId == flowId && c.RunStatus == FlowRunStatus.History).Select(c => new TaskInstance()
                    {
                        WorkFlowDefId = c.WorkFlowInstance.WorkFlowDef.Id,
                        WorkFlowDefKey = c.WorkFlowInstance.WorkFlowDef.WorkFlowDefKey,
                        WorkFlowDefName = c.WorkFlowInstance.WorkFlowDef.WorkFlowDefName,
                        InstanceId = c.InstanceId,
                        NodeDefId = c.NodeDefId,
                        TaskId = c.Id,
                        DealUserId = c.DealUserId,
                        DealUser = c.DealUser,
                        DealRemark = c.DealRemark,
                        DealDate = c.DealDate,
                        FlowVersion = c.WorkFlowInstance.Version

                    }).OrderByDescending(c => c.DealDate).ToList();

                instance.ForEach(c =>
                {
                    var data = GetCurrentVersionFlow(c.WorkFlowDefId, c.FlowVersion);
                    var currentNode = data.Nodes.FirstOrDefault(n => n.Id == c.NodeDefId);
                    if (currentNode != null)
                        c.NodeDefName = currentNode.NodeDefName;
                });


                return instance;
            }
        }

        /// <summary>
        /// 得到运行中的流程图
        /// </summary>
        /// <param name="flowId"></param>
        /// <returns></returns>
        public Bitmap GetRunBitmap(string flowId)
        {
            Bitmap bitmap = null;
            using (var context = new WorkFlowDbContext())
            {
                var flowRecord = context.WorkFlowInstances.FirstOrDefault(c => c.Id == flowId);

                if (flowRecord != null)
                {
                    var model = GetCurrentVersionFlow(flowRecord.WorkFlowDefId, flowRecord.Version);
                    var nodes = model.Nodes;
                    var nodelinks = model.NodeLinks;

                    var currentNode = flowRecord.WorkFlowTasks.FirstOrDefault(c => c.RunStatus == FlowRunStatus.Run);
                    //如果为null，则表示流程已经完成
                    if (currentNode != null)
                    {
                        var currentNodeDef = model.Nodes.FirstOrDefault(c => c.Id == currentNode.NodeDefId); //currentNode.FlowNodeDef;
                        bitmap = new DrawingCurve().DrawingFlow(nodes, nodelinks, currentNodeDef);
                    }
                    else
                    {
                        var currentNodeDef = nodes.FirstOrDefault(c => c.NodeType == NodeType.End);
                        bitmap = new DrawingCurve().DrawingFlow(nodes, nodelinks, currentNodeDef);
                    }
                }

            }
            return bitmap;
        }
        #endregion

        #region private method

        //返回目标节点
        private TaskDefinition getTargetNode(WorkFlowModel flowModel, List<TaskLink> nodelinks, string condition)
        {
            TaskDefinition targetNode = null;
            if (nodelinks.Count == 1)
            {
                targetNode = flowModel.Nodes.FirstOrDefault(c => c.Id == nodelinks[0].TargetId);

            }
            else
            {
                if (String.IsNullOrEmpty(condition))
                {
                    throw new ArgumentNullException("参数condition不能为空", condition);
                }
                var nodelink = nodelinks.FirstOrDefault(c => c.Condition == condition);
                if (nodelink == null)
                {
                    throw new Exception("未知的转出条件");
                }
                targetNode = flowModel.Nodes.FirstOrDefault(c => c.Id == nodelink.TargetId);
            }


            return targetNode;
        }



        public List<TaskCondition> GetNodeOutConditions(string nodeRecordId)
        {
            List<TaskCondition> list = new List<TaskCondition>();
            using (var context = new WorkFlowDbContext())
            {
                var sourcenodeRecord = context.WorkFlowTasks.FirstOrDefault(c => c.Id == nodeRecordId);
                if (sourcenodeRecord == null)
                {
                    throw new Exception(string.Format("未找到Flow_NodeRecord的记录:{0}", nodeRecordId));

                }
                if (sourcenodeRecord.RunStatus == FlowRunStatus.History)
                {
                    throw new Exception("流程已被操作过");
                }
                var model = GetCurrentVersionFlow(sourcenodeRecord.WorkFlowInstance.WorkFlowDefId, sourcenodeRecord.WorkFlowInstance.Version);
                var flowNodeDef = model.Nodes.FirstOrDefault(c => c.Id == sourcenodeRecord.NodeDefId);
                if (flowNodeDef != null)
                {
                    var nodelinks = model.NodeLinks.Where(c => c.SourceId == flowNodeDef.Id).ToList();//flowNodeDef.FlowNodeLinks_SourceId.ToList();

                    list = nodelinks.Select(c => new TaskCondition()
                    {
                        Name = c.LinkName,
                        Condtion = c.Condition
                    }).ToList();


                }

            }
            return list;


        }

        public List<Models.Task> GetTaskNodes(string nodeRecordId)
        {
            List<Models.Task> list = new List<Models.Task>();
            using (var context = new WorkFlowDbContext())
            {
                var sourcenodeRecord = context.WorkFlowTasks.FirstOrDefault(c => c.Id == nodeRecordId);
                if (sourcenodeRecord == null)
                {
                    throw new Exception(string.Format("未找到Flow_NodeRecord的记录:{0}", nodeRecordId));

                }
                if (sourcenodeRecord.RunStatus == FlowRunStatus.History)
                {
                    throw new Exception("流程已被操作过");
                }
                else
                {
                    var model = GetCurrentVersionFlow(sourcenodeRecord.WorkFlowInstance.WorkFlowDefId, sourcenodeRecord.WorkFlowInstance.Version);
                    list =
                        model.Nodes.Where(c => c.FlowDefId == sourcenodeRecord.WorkFlowInstance.WorkFlowDefId && c.NodeType == NodeType.Task)
                            .Select(c => new Task()
                            {
                                Id = c.Id,
                                TaskName = c.NodeDefName
                            })
                            .ToList();
                }


            }
            return list;

        }



        public List<Models.Task> GetFlowTasks(string flowDefId, int version)
        {
            List<Models.Task> list = new List<Models.Task>();
            var model = GetCurrentVersionFlow(flowDefId, version);
            if (model != null)
            {
                list =
                  model.Nodes.Where(
                      c => c.FlowDefId == flowDefId && c.NodeType == NodeType.Task)
                      .Select(c => new Task()
                      {
                          Id = c.Id,
                          TaskName = c.NodeDefName
                      }).ToList();

            }
            return list;

        }

        private WorkFlowModel GetCurrentVersionFlow(string flowDefId, int? flowVersion = null)
        {

             using (var context = new WorkFlowDbContext())
            {
                WorkFlowVersion version;
                var data = context.WorkFlowDefs.Find(flowDefId);
                if (data == null)
                {
                    throw new Exception("让找不到流程定义");
                }
                if (flowVersion.HasValue)
                {
                    version = context.WorkFlowVersions.OrderByDescending(c => c.VersionNumber).FirstOrDefault(x => x.WorkFlowDefId == flowDefId && x.VersionNumber == flowVersion.Value);
                }
                else
                {
                    version = context.WorkFlowVersions.OrderByDescending(c => c.VersionNumber).FirstOrDefault(x => x.WorkFlowDefId == flowDefId);
                }


                if (version != null && !String.IsNullOrEmpty(version.WorkFlowDocument))
                {
                    WorkFlowModel flowDef = new WorkFlowModel();
                    ;
                    WorkFlowDocument document = XmlSerializeUtil.Deserialize(typeof(WorkFlowDocument), version.WorkFlowDocument) as WorkFlowDocument;

                    flowDef.Id = data.Id;
                    flowDef.WorkFlowDefKey = data.WorkFlowDefKey;
                    flowDef.WorkFlowDefName = data.WorkFlowDefName;
                    flowDef.CategoryId = data.CategoryId;
                    if (data.WorkFlowCategory != null)
                    {
                        flowDef.CategoryName = data.WorkFlowCategory.CategoryName;

                    }
                    flowDef.CreateDate = data.CreateDate;
                    if (document != null)
                    {
                        flowDef.NodeLinks = document.NodeLinks;
                        flowDef.Nodes = document.Nodes;
                    }
                    return flowDef;
                     
                }
            }
            return null;
        }

        #endregion
    }
}
